/*
 * FixedSizeBlockFile_test.cpp
 *
 *  Created on: Oct 14, 2012
 *      Author: m
 */

#include "FixedSizeBlockFile.h"
#include <memory>
#include <queue>

#define _BLOCKSIZE 10

/*
 * Modo de Uso:
 *
 *  fsbf_ts test_id output [...]
 *
 *  Descripción:
 *  Test Suite de la clase FixedSizeBlockFile, para utilizarlos se debe indicar
 *  el nº de prueba a ejecutar, el nombre del archivo de salida y
 *  otros parámetros que dependen de la prueba seleccionada.
 *
 *  Los tests son:
 *
 *  1. MODO 1:
 *     Descrición:
 *          Escritura de Bloques de tamaño fijo, con contenido sequencial.
 *
 *     Modo de Uso:
 *          fsbf_ts 1 output
 *
 *  2. MODO 2:
 *     Descripción:
 *          Lectura de Bloques de tamaño fijo, en el siguiente orden: L5L8L7L6L1L0L1L0L0L9L8L9L2L3L4L9.
 *          A los bloques leidos se les aplica una verificación (se suponen de contenido secuencial).
 *          Finalmente se genera un archivo de salida indicando nº de bloque leido y resultado de la
 *          verificación
 *
 *
 *     Modo de Uso:
 *          fsbf_ts 2 output input
 */

using namespace physical;

bool verifyBlock( byteStream block, size_t blockSize, blockNumber blockId  );
void populateBlock( byteStream block, size_t blockSize, blockNumber blockId  );

int main ( int argc, char* argv[] )
{
    std::unique_ptr<FixedSizeBlockFile> blockFile;
    int testId;
    std::unique_ptr<byteStream> buffer;
    std::queue<blockNumber> blocksToRead;
    char *outFileName, *inFileName;
    size_t blockSize;
    std::fstream textFile;

    if ( argc < 2 )
        return 1;

    testId = atoi( argv[1] );
    blockSize = _BLOCKSIZE; // hacerlo parametrizable!

    switch ( testId )
    {
        // Escritura de archivo de bloques
        case 1:

            // Parseo argumentos propios de la prueba
            outFileName = argv[2];

            blockFile.reset( new FixedSizeBlockFile(blockSize) );
            buffer.reset( new byte[blockSize] );

            blockFile->open( outFileName, std::ios_base::out | std::ios_base::trunc );

            for ( int blockId=0; blockId<10; ++blockId )
            {
                populateBlock( buffer.get(), blockSize, blockId );
                blockFile->writeBlock( blockId, buffer.get() );
            }

            blockFile->close();

            break;

        case 2:

            outFileName = argv[2];
            inFileName  = argv[3];

            blockFile.reset( new FixedSizeBlockFile(blockSize) );
            buffer.reset( new byte[blockSize] );

            blockFile->open( inFileName, std::ios_base::in );
            textFile.open( outFileName, std::ios_base::out | std::ios_base::trunc );

            // Se inizializa la lista de bloques a leer.
            blocksToRead.push(5);
            blocksToRead.push(8);
            blocksToRead.push(7);
            blocksToRead.push(6);
            blocksToRead.push(1);
            blocksToRead.push(0);
            blocksToRead.push(1);
            blocksToRead.push(0);
            blocksToRead.push(0);
            blocksToRead.push(9);
            blocksToRead.push(8);
            blocksToRead.push(9);
            blocksToRead.push(2);
            blocksToRead.push(3);
            blocksToRead.push(4);
            blocksToRead.push(9);

            // Se leen los bloques uno a uno y se verifica su contenido.
            while ( !blocksToRead.empty() )
            {
                int blockId = blocksToRead.front();
                blocksToRead.pop();

                blockFile->readBlock( blockId, buffer.get() );

                // verificar el bloque
                bool verificationResult = verifyBlock( buffer.get() , blockSize, blockId );

                // print resultado de la lectura
                textFile << blockId << " " << ( verificationResult? "ok" : "error" ) << std::endl;
            }

            blockFile->close();
            textFile.close();
            break;

        default:
            return 2;
    }

    return 0;
}

bool verifyBlock( byteStream block, size_t blockSize, blockNumber blockId )
{
    for ( size_t byteIndex = 0; byteIndex < blockSize; ++byteIndex )
    {
        if ( block[byteIndex] != ( blockId * blockSize + byteIndex ) )
            return false;
    }
    return true;
}

void populateBlock( byteStream block, size_t blockSize, blockNumber blockId )
{
    for ( size_t byteIndex=0; byteIndex < blockSize; ++byteIndex )
    {
        block[byteIndex] = blockId * blockSize + byteIndex;
    }
}
